"""
PatternCompletion.py

Thu Oct 18 08:55:26 CEST 2012

Major class to perform the simulation of pattern completion
according to Gibson & Robinson, 1992

Example:
 
>>> mynetwork = Simulation(1000, 0.5, 0.1, 50, 0.4333, seed=100)
# will create the connectivity matrix (W), the original pattern (Z)
# the matrix of random patterns of activity (Y) and the matrix of
# synaptic weights (W) 

>>> mynetwork(seed=200)
# will update the connectivity matrix and the matrix of synaptic weights
# original pattern and the matrix of random patterns will remain the same
X=mynetwork.Z
>>> mynetwork.recall(mynetwork.Z, ).J # returns the matrix of synaptic weights

"""
from network import topology
from firings import Pattern, generate
from plasticity import clipped_Hebbian
from STDP import delta_t
import numpy as np

class Simulation(object):
    def __init__(self, n, c, a, m, g1, seed=None):
        """
        Create the connectivity matrix W and generate the 
        matrix of synaptic weigths J according to
        Gibson & Robinson 1992
        
        Arguments:
        n       -- number of cells
        c       -- connection probability
        a       -- activity of a pattern
        m       -- number of patterns to store
        g1      -- slope of the inhibitory component

        """
        self.n = n
        self.c = c
        self.a = a
        self.m = m
        self.g1 = g1

        # this can be only return by getters
        self.W = None
        self.Z = Pattern(self.n, self.a)
        self.Y = generate(self.Z, self.m)
        self.J = None

        # self.seed = seed
        self.__call__(seed) # will update self.seed

    def __call__(self, seed):
        """
        create a connectivity matrix (W) and update
        the matrix of synaptic weigths (J) according
        to the sequence of patterns (Y)
        """
        self.seed = seed # update seed

        self.W = topology(self.n, self.c, self.seed)
        self.J = clipped_Hebbian(self.Y, self.W) # time consuming step

    
    def recall(self, X, nrecall):
        """
        returns a matrix with the vector of activities in response 
        to an input vector upon progressive recall
        
        The matrix has the shape nrecall*ncells, the first row of the
        matrix is the vector of the activities itself
        """

        n, J, g1 = self.n, self.J, self.g1 # param readout

        activity = np.empty((nrecall+1, self.n))
        
        activity[0] = np.array(X) # first the initial activity
        for i in xrange(1, nrecall+1):
            h = np.inner(J.T, X) / float(n)
            X = (h < g1*np.mean(X) ).choose(1,0)
            activity[i] = X

        return(activity)
            
        
def calculate_overlap(vector, dt_list):
    """ 
    perform 50 simulations with different seed for the connectivity 
    matrix (W)

    X   -- a vector of initial activities
    dt  -- time between pre and post synaptic timing for plasticity rule
    
    mynetwork = Simulation(3000, 0.5, 0.1, 50, 0.433, 0)

    # a vector of 50 simulations
    np.savetxt('./data/[dt=%2d].out')
    """
    ncells = 3000   # number of cells
    c = 0.5         # connection probability
    a = 0.1         # activity of a pattern
    m = 50          # number of patterns to store
    g1 = 0.433      # slope of inhibitory component

    nrecall = 10 # progressive recalls

    seedlist = np.arange(50, 2500, 50) # 49 seeds


    mynetwork = Simulation(ncells, c, a, m, g1, 0  ) # first seed is zero
    mynetwork.J = mynetwork.J*delta_t(dt)

    # create 
    for s in seedlist:
        mynetwork(seed=s) # create new topology
        # compute the firings after 10 recalls
        firings = mynetwork.recall(X=vector, nrecall=10)        
        for t in dt_list:
            mynetwor.J = mynetwork
        
        overlaps = [for n in 10 get_overlap(mynetwork.Z, firings[n])]

         
if __name__ == '__main__':
    pass
    
    

    
    
